/*
 * Copyright (c) 2011-2022, baomidou (jobob@qq.com).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.baomidou.mybatisplus.extension.conditions.query;

import com.baomidou.mybatisplus.core.conditions.AbstractJoinWrapper;
import com.baomidou.mybatisplus.core.conditions.SharedString;
import com.baomidou.mybatisplus.core.enums.BaseFuncEnum;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.ArrayUtils;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.core.toolkit.ExceptionUtils;
import lombok.AllArgsConstructor;
import lombok.Data;


/**
 * 本类使用BasicJoinQueryWrapper.ModelProperty 来构造多表查询条件
 * 主要搭配myabtis plus advance 和 mybatis x 插件一起使用
 * 普通开发者请使用LambdaJoinQueryWrapper
 * todo 需要优化本类代码
 * demo代码：--如果不手动设置select 则会select user.*,school.*
 *         BasicJoinQueryWrapper<User> wrapper = new BasicJoinQueryWrapper<>(User.class);
 *         wrapper.innerJoin(School.class);
 *         wrapper.eq(new BasicJoinQueryWrapper.ModelProperty(User.class,"schoolId"),1);
 *         wrapper.select(new BasicJoinQueryWrapper.ModelProperty(User.class,"schoolId"));
 *         wrapper.select(new BasicJoinQueryWrapper.ModelProperty(User.class,"userId"));
 *         wrapper.select(new BasicJoinQueryWrapper.ModelProperty(User.class,"name"));
 *         wrapper.select(new BasicJoinQueryWrapper.ModelProperty(School.class,"schoolName"));
 *         wrapper.select(new BasicJoinQueryWrapper.ModelProperty(School.class,"id"));
 *         wrapper.select(new BasicJoinQueryWrapper.ModelProperty(School.class,"remark"));
 *         return
 *                 mapper.selectJoinList(wrapper);
 * @author wanglei
 * @since 2022-03-17
 */
public class BasicJoinQueryWrapper<T> extends AbstractJoinWrapper<T, BasicJoinQueryWrapper.ModelProperty,
        BasicJoinQueryWrapper<T>> {

    /**
     * 主表model的class
     */
    private Class<?> mainClass;



    public BasicJoinQueryWrapper(Class<?> mainClass) {
        super(mainClass);
        this.mainClass = mainClass;
        super.initNeed();
        initLogicDelete(mainClass);
    }

    @Override
    protected BasicJoinQueryWrapper<T> instance() {
        return new BasicJoinQueryWrapper(mainClass);
    }

    @Override
    public BasicJoinQueryWrapper<T> select(ModelProperty... columns) {
        if (ArrayUtils.isNotEmpty(columns)) {
            for (ModelProperty column : columns) {
                selectColumns.add(SelectColumn.of(column.modelClass, getCache(column.getModelClass(),column.getPropertyName()).getColumn()));
            }
        }
        return (BasicJoinQueryWrapper<T>) typedThis;
    }

    /**
     * 查询函数列,如果column不指定，则查询 *
     * <p>select xx(column) as alias</p>
     */
    public final BasicJoinQueryWrapper<T> selectFun(BaseFuncEnum fun, String alias, ModelProperty column) {
        String columnStr = column == null ? "*" : aliasMap.get(column.modelClass) + Constants.DOT +  getCache(column.getModelClass(),column.getPropertyName()).getColumn();
        String funStr = String.format(fun.getSql(), columnStr);
        this.funSqlSelect.add(new SharedString(funStr + Constants.AS + alias));
        return (BasicJoinQueryWrapper<T>)typedThis;
    }

    /**
     * inner join
     *
     * @param joinClass join的表的类
     * @return this
     */
    public BasicJoinQueryWrapper<T> innerJoin(Class<?> joinClass) {
        pubJoin(joinClass, Constants.INNER_JOIN);
        return  this;
    }

    /**
     * 软删除字段处理
     * @param joinClass
     */
    @Override
    protected void initLogicDelete(Class<?> joinClass){
        TableInfo tableInfo = TableInfoHelper.getTableInfo(joinClass);
        if(tableInfo.getLogicDeleteFieldInfo()!=null){
            eq(new ModelProperty(joinClass,tableInfo.getLogicDeleteFieldInfo().getProperty())
                ,parseLogicNotDeleteValue(tableInfo.getLogicDeleteFieldInfo()));
        }
    }

    /**
     * left join
     *
     * @param joinClass join的表的类
     * @return this
     */
    public BasicJoinQueryWrapper<T> leftJoin(Class<?> joinClass) {
        pubJoin(joinClass, Constants.LEFT_JOIN);
        return  this;
    }

    /**
     * inner join
     *
     * @param joinClass join的表的类
     * @return this
     */
    public BasicJoinQueryWrapper<T> rightJoin(Class<?> joinClass) {
        pubJoin(joinClass, Constants.RIGHT_JOIN);
        return  this;
    }


    @Override
    protected String columnToString(ModelProperty column) {
         if(!super.aliasMap.containsKey(column.getModelClass())){
             throw ExceptionUtils.mpe("not join class: \"%s\".", column.getModelClass().getName());
         }
         return super.aliasMap.get(column.getModelClass()) + "." + getCache(column.modelClass,column.getPropertyName()).getColumn() ;
    }

    /**
     * 查询/过滤条件字段
     */
    @Data
    @AllArgsConstructor
    public static class ModelProperty{

        /**
         * 类名
         */
        private Class<?> modelClass;

        /**
         * 属性名
         */
        private String propertyName;
    }
}
